var fs = require('fs');
const path = require('path');
var temDir;
var remoteSaveBase;
var request = require('request');
var mkdirp = require('mkdirp');
const url = require('url');
var requestJar = request.jar(); // 用于储存cookie；
var request = request.defaults({
    jar: requestJar
});
var mockList = [];

//mock假数据， 将线上环境的路由   ajax访问 映射到开发环境
var redirect = function(route) {
    return function(req, res, next, para) {
        res.writeHead(302, {
            'Location': route + para
        });
        res.end();
    }
};
var ajax = function(route, obj_json) {
    return function(req, res) {
        res.setHeader("Access-Control-Allow-Origin", true);
        res.setHeader("Content-Type", "application/json;charset=utf-8");
        if (route) {
            //          require.cache[path.join(__dirname, '../.', route)]
            res.end(JSON.stringify(require(route)));
        } else {
            res.end(JSON.stringify(obj_json));
        }
    }
}
var ajaxSync = function(route, obj_json) {
    return function(req, res) {
        res.setHeader("Access-Control-Allow-Origin", true);
        res.setHeader("Content-Type", "application/json;charset=utf-8");
        if (route) {
            res.end(JSON.stringify(readJsonSync(route)));
        } else {
            res.end(JSON.stringify(obj_json));
        }
    }
}
var ajaxDirSync = function({
    dirBasePath,
    pathPrefix
} = {
    dirBasePath: './',
    pathPrefix: '/'
}) {
    return function(req, res, next) {
        const {
            pathname: reqPath
        } = {
            ...url.parse(req.url)
        };
        let prefixReg;
        if (pathPrefix) {
            prefixReg = new RegExp(`^${pathPrefix}`);
        }
        let resPath;
        let subPath = reqPath;
        if (prefixReg) {
            if (prefixReg.test(reqPath)) {
                subPath = reqPath.replace(prefixReg, '');
            } else {
                return next();
            }
        }
        resPath = path.resolve(dirBasePath, subPath);
        res.setHeader("Access-Control-Allow-Origin", true);
        let resData;
        if (resPath.endsWith(".json")) {
            res.setHeader("Content-Type", "application/json;charset=utf-8");
            resData = readFile(resPath);
        } else {
            res.setHeader("Content-Type", "application/octet-stream");
            // res.setHeader("Content-Disposition", "attachment; filename=filename.ext");
            resData = fs.readFileSync(resPath);
        }
        res.end(resData);
    }
}
var render_html = function(str_html) {
    return function(req, res) {
        res.setHeader("Content-Type", "text/html");
        res.end(str_html);
    }
}
var render_js = function(str_js) {
    console.log("str_js", str_js);
    return function(req, res) {
        console.log("req, res", req, res);
        res.setHeader("Content-Type", "text/javascript");
        res.end(str_js);
    }
}
var readFile = function(filePath) {
    // try {
    var str = fs.readFileSync(filePath, 'utf8');
    // } catch (e) {
    //     console.error('readFile ', filePath, ' error!');
    //     console.error(e);
    // }
    return str;
}
var readJsonSync = function(filePatch) {
    return JSON.parse(readFile(filePatch));
}

var getDateInfo = function() {
    return (new Date).toLocaleString().replace(/[:]/g, '');
}
var requestRemote = function(remote) {
    return function(req, res) {
        var url = req.url;
        //      console.log("url", url);
        var uri = remote + url;
        var timeout = mockSettings.timeout || 10000
        var x = request({
            uri,
            gzip: true,
            timeout
        }, function(error, response, body) {
            if (remoteSaveBase) {
                var savePath = remoteSaveBase + url.replace(/[\\\/:*?"<>|]/g, '_') + '/';
                // 用于清理_=(时间戳)的参数。2033年会出问题。
                savePath = savePath.replace(/_=1[\d]{12}/, '');
                mkdirp(savePath, function(err) {
                    if (err) {
                        console.error(err);
                    }
                    var saveFileName = savePath + getDateInfo() + '.json';
                    fs.writeFile(saveFileName, body, 'utf8', (err) => {
                        if (err) {
                            console.error(err);
                        }
                    });
                })
            }
        })
        const handleError = prefix => e => {
            console.error(prefix, e, url);
            if (e.code === "ETIMEDOUT") {
                res.status(504)
            } else {
                res.status(502)
            }
            res.end([`Request remote error:`, `${prefix}:`, e, url, "See more Error detail on console"].join("\n"));
        }
        try {
            // console.log('Object.keys(req.headers)', Object.keys(req.headers));
            function fixHeader({
                parents
            }) {
                parents.forEach(x => {
                    const setHeaderOld = x.setHeader
                    x.__old__setHeader = setHeaderOld
                    x.setHeader = function setHeader(name, value) {
                        // console.log('name, value', name, value);
                        setHeaderOld.call(x, name.trim(), value)
                    };
                });
                return {
                    rollback: () => {
                        parents.forEach(x => {
                            x.setHeader = x.__old__setHeader
                            delete x.__old__setHeader
                        });
                    }
                }
            }
            const {
                rollback: rollbackReq
            } = fixHeader({
                parents: [req]
            });
            const {
                rollback: rollbackAfterReq
            } = fixHeader({
                parents: [x, res]
            });
            req.pipe(x).on('error', handleError('req pipe')).on('finish', function() {
                rollbackReq()
            })
            // console.log('Object.keys(x.headers)', Object.keys(x.headers));
            res.setHeader('x-request-remote-remote-uri', uri);
            x.pipe(res).on('error', handleError('res pipe')).on('finish', function() {
                rollbackAfterReq()
            })
        } catch (e) {
            handleError('req pipe res')(e)
        } finally {}
    }
}

var routerReplace = function(reg, rep = '') {
    return function(req, res, next) {
        var treg = new RegExp(reg);
        req.url = req.url.replace(treg, rep);
        next();
    }
}

//var mocks = {
//   重定向
//  	'/commodity/getStuBuy.do': redirect('/course/u-course.html'),
//
//   json
//  	'/index/bannerList.do': ajax('../src/ajax/index/bannerList.json'),
//  	'/comments/add.do': ajax(null, {
//  		isSuccess: 1
//  	}),
//    '/$%7Bctx%7D/insure/car/distribution': ajax('./json/distribution.json'),
//
//    渲染文件
//  	'/comments/lesson_page_search.do': render_html(readFile(dist_dir.main + '/sociality/lessonPageCommentsList.html'))
//    '/$%7Bctx%7D/static/js/car/car-perfectInfo-control.js': render_js(readFile(dist_dir.js + '/car-perfectInfo-control.js')),
//  '/api/user/getUserInfo': ajax('./test/json/getUserInfo.json'),
//  '/api': requestRemote('http://bxs.winbaoxian.cn')
//
//}
//mockList = [{
//  'reg': '/yuanbao/goods/trade/get',
//  'handle': ajaxSync('./test/json/goods-trade-get.json')
//}, {
//  'reg': '/yuanbao/goods/list',
//  'handle': ajaxSync('./test/json/goods-list.json')
//}, {
//  'reg': '/weChat/userinfo/get',
//  'handle': ajaxSync('./test/json/userinfo-get.json')
//}, {
//  'reg': '/api',
//  'handle': requestRemote('http://bxs.winbaoxian.cn')
//}];
//var delay = 2000;
//var delay = 0;
var mockSettings;
var middleware = function(settings) {
    if (typeof settings != "string") {
        settings = "mockSettings.js";
    }
    // if (typeof settings == "string") {
    //     mockSettings = eval(readFile(settings));
    // }
    // temDir = mockSettings.temDir;
    // if (temDir) {
    //     temDir = temDir + '/';
    //     remoteSaveBase = temDir + 'remoteAuto/' + getDateInfo() + '/';
    // }
    return function(...args) {
        const expressMiddleWare = function(req, res, next) {
            // 本中间件用express写法
            // var mockSettings = eval(readFile("mockSettings.js"));
            // mockList = mockSettings.mockList;
            if (typeof settings == "string") {
                mockSettings = eval(readFile(settings));
            }
            temDir = mockSettings.temDir;
            if (temDir) {
                temDir = temDir + '/';
                if (remoteSaveBase == undefined) {
                    remoteSaveBase = temDir + 'remoteAuto/' + getDateInfo() + '/';
                }
            } else {
                remoteSaveBase = undefined;
            }
            mockList = mockSettings.mockList;
            var delay = mockSettings.delay;
            var dist_dir = mockSettings.dist_dir;
            var url = req.url,
                parameter = "";
            if (url.indexOf('?') > 0) {
                var index = url.indexOf('?');
                parameter = index > 0 ?
                    url.slice(index) :
                    "";
                url = url.slice(0, url.indexOf('?'));
            }
            var tryMockItem = function(i) {
                // 尝试用mockList标号i的item进行匹配和运行
                // 每次都要重新获取url，因为有的中间件会修改url，供后续中间件使用
                var url = req.url,
                    parameter = "";
                if (url.indexOf('?') > 0) {
                    var index = url.indexOf('?');
                    parameter = index > 0 ?
                        url.slice(index) :
                        "";
                    url = url.slice(0, url.indexOf('?'));
                }
                var tryNext = function() {
                    tryMockItem(i + 1);
                };
                if (i < mockList.length) {
                    var mockItem = mockList[i];
                    if (!mockItem) {
                        // 跳过空项
                        return tryNext();
                    }
                    var reg = new RegExp(mockItem.reg);
                    var handle = mockItem.handle;
                    var itemDelay = mockItem.delay;
                    if (reg.test(url)) {
                        // reg代表的正则表达式命中URL
                        var delayRes = itemDelay || delay;
                        return setTimeout(function() {
                            try {
                                // 中间件暂时仅支持express写法
                                handle(req, res, function() {
                                    return tryNext();
                                }, parameter);
                                //                  next();
                            } catch (e) {
                                console.error(e);
                                res.status(500).end([`At item index(from zero) ${i}:`, `Item reg:${mockItem.reg}`, e, "See more Error detail on console"].join("\n"));
                            }
                        }, delayRes);
                        done = true;
                    } else {
                        // reg代表的正则表达式与URL不匹配，试下一个
                        return tryNext();
                    }
                } else {
                    // MockList尝试结束，所有item的reg都不命中，转移控制权
                    return next();
                }
            }
            tryMockItem(0);
        };
        if (args.length == 3) {
            // express like
            const [req, res, next] = args;
            if (!res.status) {
                res.status = function(code) {
                    res.statusCode = code;
                    return res;
                }
            }
            expressMiddleWare(req, res, next);
        } else {
            // koa
            const [ctx, next] = args;
            const res = ctx.res;
            const req = ctx.req;
            const end = res.end;
            return new Promise(function(resolve, reject) {
                res.status = function(code) {
                    res._statusSetted = true;
                    ctx.response.status = code;
                    return res;
                }
                res.end = function() {
                    if (!res._statusSetted) {
                        res.status(200);
                    }
                    end.apply(this, arguments);
                    resolve();
                };
                expressMiddleWare(req, res, reject);
            }).catch(next);
        }
    }
}
exports.middleware = middleware;

exports.mockList = mockList;
